#include<iostream.h>
#include<iomanip.h>
#include<fstream.h>
#include<string.h>
#include<stdlib.h>
#define DEFINE 1
#define EXPAND 0
#define FALSE -1

int strcmpisi(char *i1, char *i2)
{
 char s[81],t[81];
 strcpy(s,i1);strcpy(t,i2);

 int l1= strcspn(i1," ");
 int l2= strcspn(i2," ");
 if (l1!=l2) return 1;

 s[l1]='\0';  t[l2]='\0';
 return (strcmpi(s,t));
}

ofstream tgt("OUT.ASM",ios::out);

class DefTab
{
 private:
  char Name[10][20];
  struct {
   char opcode[7];
   char operand[19];
  }  Defs[40];
  int start[20],end[20];
  int DefPtr;
  int MacNum;
  int Mode;

 //Member Functions

  void StartMacro(char *,char *);
  void EndMacro(void);
  void AddLine(char *, char*);
  void ExpandMacro(char *);
  int  IsMacro(char *opcode);
 public:
  DefTab(char *fn)
   {
     DefPtr=0; MacNum=0; Mode = EXPAND;
   }
  void ProcessMacro(char *,char*,char *);
};

void DefTab::StartMacro(char *label,char *operand)
{
  start[MacNum]=DefPtr;
  strcpy(Name[MacNum],label);
  Mode = DEFINE;
}

void DefTab::EndMacro(void)
{
  end[MacNum++]=DefPtr-1;
  Mode = EXPAND;
}

void DefTab::AddLine(char *opcode, char *operand)
{
 strcpy(Defs[DefPtr].opcode,opcode);
 strcpy(Defs[DefPtr++].operand,operand);
}

void DefTab::ExpandMacro(char *opcode)
{
 int idx;

 idx=IsMacro(opcode);
 if(idx==FALSE) return;

 for(int i=start[idx];i<=end[idx];i++)
 {
  if (IsMacro(Defs[i].opcode)!=FALSE)
      ExpandMacro(Defs[i].opcode); //Recursive Expansion
  else
   tgt<<"         "<<Defs[i].opcode<<"  "<<Defs[i].operand<<"\n";
 }
}


int DefTab::IsMacro(char* opcode)
{
 int found=0;
 for(int i=0;(i<10)&&(!found);i++)
     if(!strcmpisi(opcode,Name[i]))
			      found=1;

 if (found) return (i-1);
 else return FALSE;
}

void DefTab::ProcessMacro(char *label,char *opcode, char *operand)
{
 if (!strcmpisi("MACRO ",opcode))
     {  StartMacro(label,operand);return; }
 if (!strcmpisi("MEND  ",opcode))
     { EndMacro();return; }
 if (Mode==DEFINE)
    {
      AddLine(opcode,operand);
      return; }
 else
 {
   if (IsMacro(opcode)==FALSE)
    {
     tgt <<label<<" "<<opcode<<"  "<<operand<<"\n";
     cout <<label<<" "<<opcode<<"  "<<operand<<"\n";
    }
   else
   ExpandMacro(opcode);
 }
}

/*
BYTES
     1-8  Label
       9  Blank
    10-15 Operation code
    16-17 Blank
    18-35 Operand
    36-66 Comment*/

char label[9],opcode[7],operand[19];
ifstream src;

int analyze()
{
 int i;
 char ch,line[81];
do
 {
  src.get(line,80,'\n'); src.get(ch); //Read a line
  if(src.fail()) return(0);

  for(i=0;i<8;i++)   label[i]=line[i]; 		label[8]='\0';
  for(i=9;i<15;i++)  opcode[i-9]=line[i];	opcode[6]='\0';
  for(i=17;i<35;i++) operand[i-17]=line[i]; 	operand[18]='\0';
 } while(label[0]=='.');
}

void main()
{
 char fname[20];
 DefTab DEFTAB("out.asm");
 cout<<"Filename:";cin>>fname;
 src.open(fname,ios::in);
 if (!src) cout<<"File Open Error!";
 else
  {
   while(!src.eof())
   {
    if(!analyze()) break;
    DEFTAB.ProcessMacro(label,opcode,operand);
   }
   src.close();
  }
 tgt.close();
}

